home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume8 / cz / part11 < prev    next >
Encoding:
Text File  |  1989-09-30  |  57.1 KB  |  1,921 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v08i075: cz text to PostScript system, part 11 of 14
  3. from: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: howard@dahlbeck.ericsson.se (Howard Gayle)
  5.  
  6. Posting-number: Volume 8, Issue 75
  7. Submitted-by: howard@dahlbeck.ericsson.se (Howard Gayle)
  8. Archive-name: cz/part11
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 11 (of 14)."
  18. # Contents:  cz0.c
  19. # Wrapped by howard@dahlbeck on Mon Sep 25 07:15:24 1989
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'cz0.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'cz0.c'\"
  23. else
  24. echo shar: Extracting \"'cz0.c'\" \(54952 characters\)
  25. sed "s/^X//" >'cz0.c' <<'END_OF_FILE'
  26. X/*
  27. X * cz0 - Convert text in any octet-based character set into PostScript.
  28. X */
  29. X
  30. X#include <stdio.h>
  31. X#include <howard/port.h>
  32. X#include <howard/version.h>
  33. X#include <howard/usage.h>
  34. X
  35. XMAINVER ("@(#)$Header: cz0.c,v 2.25 89/08/21 10:54:56 howard Exp $");
  36. XUSAGE ("[-o file] {-command argument}");
  37. X
  38. X#include <ctype.h>
  39. X#include <string.h>
  40. X#include <time.h>
  41. X#include <howard/a2.h>
  42. X#include <howard/malf.h>
  43. X#include <howard/registers.i>
  44. X#include "FREEZE.i"
  45. X#include "cz.h"
  46. X#include "ps-abbrev.i"
  47. X#include "cz0.h"
  48. X#include "state0.i"
  49. X
  50. X/* a2ocol - convert string to output column number */
  51. X
  52. XPRIVATE ushrtT a2ocol (s, n)
  53. XbStrT s; /* Input string.*/
  54. XbStrT n; /* Field name.*/
  55. X
  56. X/* Function:
  57. X *    s is a string representation of an output column number, e.g.
  58. X *    FoldFirst.  It is either "Inf" for the maximum output column,
  59. X *    or an integer numeric literal.
  60. X * Algorithm:
  61. X *    
  62. X * Returns:
  63. X *    
  64. X * Notes:
  65. X *    
  66. X */
  67. X{
  68. Xreturn (bStrEQ (S("Inf"), s) ? MOCOL : ADA_US (s, n, 0, MOCOL));
  69. X}
  70. X
  71. X/* addFnt - add a font to fonts[] if it's not already there */
  72. X
  73. XPRIVATE void addFnt (f, s)
  74. XR2 bStrT f; /* Font name.*/
  75. X   boolT s; /* A symbol font.*/
  76. X
  77. X/* Function:
  78. X *    If font f is not already in the list of fonts used, add it.
  79. X *    If it *is* already in the list, make sure its stored symbol font
  80. X *    status is the same as s.
  81. X * Algorithm:
  82. X *    Linear search.
  83. X * Returns:
  84. X *    
  85. X * Notes:
  86. X *    1) It's necessary to distinguish symbol fonts from non-symbol
  87. X *       fonts because symbol fonts must not be reencoded.
  88. X */
  89. X{
  90. XR1 fontT *fp; /* Steps through fonts[].*/
  91. X
  92. Xfor (fp = fonts; (fp != fontP) && !bStrEQ (f, fp->fntName); ++fp)
  93. X   ;
  94. Xif (fp == fontP)
  95. X   {
  96. X   if (fp == &fonts[MFONTS]) malf1 (eMFonts, MFONTS);
  97. X   fp->fntName = f;
  98. X   fp->fntSymb = s;
  99. X   ++fontP;
  100. X   }
  101. Xelse if (fp->fntSymb != s)
  102. X   malf1 (eSymFnt, f);
  103. X}
  104. X
  105. X/* addso - add one state-octet pair to state table */
  106. X
  107. XPRIVATE void addso (sos, pss)
  108. XR4 bStrT sos; /* State-octet pair as a string.*/
  109. XR5 bStrT pss; /* Corresponding PostScript string.*/
  110. X
  111. X/* Function:
  112. X *    sos is a string representing a state-octet pair.
  113. X *    pss is a string containing the text to emit for that pair,
  114. X *    and optionally a new state at the end.  addso() enters
  115. X *    this into the state table, building new parts if necessary.
  116. X * Algorithm:
  117. X *    Convert state and octet to numbers.  Check pss for bad escapes.
  118. X *    If there is no entry in state table for s, make one.
  119. X *    If there is a next state at the end of pss, convert it to a number.
  120. X *    Store pss and next state for this pair.
  121. X * Returns:
  122. X *    
  123. X * Notes:
  124. X *    1) Should probably convert pss to nextc() output format here.
  125. X */
  126. X{
  127. XR6 unsigned  ns = 0; /* Next state.*/
  128. XR7 unsigned  o;      /* Octet.*/
  129. XR1 bStrT     p1;     /* General purpose.*/
  130. XR8 unsigned  s;      /* State.*/
  131. XR2 soT      *sop1;   /* Current soT.*/
  132. XR3 soT      *sop2;   /* End of new stateT.*/
  133. XR9 stateT   *sp;     /* Points to current stateT.*/
  134. X
  135. Xp1 = bStrChr (sos, SOSEP);
  136. Xif (NULBSTR == p1) malf1 (eSOSep, SOSEP, sos, pss);
  137. Xs = mra2u (sos, p1, FALSE, S("State"), (unsigned) 0, (unsigned) MSTATE,
  138. X           (bStrT *) NULL);
  139. Xo = mra2u (1 + p1, NULBSTR, FALSE, S("Octet"), (unsigned) 0, (unsigned) 255,
  140. X           (bStrT *) NULL);
  141. Xfor (p1 = pss; NULBSTR != (p1 = bStrChr (p1, E_ESC)); ++p1)
  142. X   {
  143. X   ++p1;
  144. X   if (T_RES == ncMap[B(*p1)]) malf1 (eEsc, E_ESC, B(*p1), sos, pss);
  145. X   }
  146. Xsp = states[s];
  147. Xif (((stateT *) NULL) == sp)
  148. X   {
  149. X   sp = (stateT *) mcalloc (1, sizeof (stateT), "State table");
  150. X   sop1 = (soT *) sp;
  151. X   sop2 = sop1 + 256;
  152. X   for (; sop1 != sop2; ++sop1)
  153. X      sop1->so_ps = NULBSTR;
  154. X   states[s] = sp;
  155. X   }
  156. Xp1 = bStrRChr (pss, E_ESC);
  157. Xif ((NULBSTR != p1) && (E_NEXTS == B(p1[1])))
  158. X   {
  159. X   ns = mra2u (2 + p1, NULBSTR, FALSE, S("Next state"), (unsigned) 0,
  160. X               (unsigned) MSTATE, (bStrT *) NULL);
  161. X   *p1 = EOS;
  162. X   }
  163. Xif (strlen (pss) > MPSSTR) malf1 (eBigPS, sos, MPSSTR, pss);
  164. Xsop1 = ((soT *) sp) + o;
  165. Xsop1->so_nxt = ns;
  166. Xsop1->so_ps = mcpstr (pss);
  167. Xif (DB(D_OCT))
  168. X   FPRINTF (stderr, "State %u Octet %c 8#%o# (%s%c%c%u)\n",
  169. X            s, o, o, sop1->so_ps, E_ESC, E_NEXTS, sop1->so_nxt);
  170. X}
  171. X
  172. X/* cmd - execute one command */
  173. X
  174. XPRIVATE void cmd (cp, ap, fn, ln)
  175. XR1 bStrT    cp; /* Command.*/
  176. X   bStrT    ap; /* Argument.*/
  177. X   cStrT    fn; /* File name.*/
  178. X   unsigned ln; /* Line number in file.*/
  179. X
  180. X/* Function:
  181. X *    Execute the given command with the given argument.  On error,
  182. X *    write an error message, using the file name and line number.
  183. X * Algorithm:
  184. X *    Linear search for command name.
  185. X * Notes:
  186. X *    1) Should use perfect hashing.
  187. X */
  188. X{
  189. XR2 bStrT p; /* General putpose.*/
  190. X
  191. Xif (DB(D_CMD)) FPRINTF (stderr, "%s: %u: %s %s\n", fn, ln, cp, ap);
  192. Xif (NULBSTR != (p = prefix (S("AutoColumn"), cp)))
  193. X   param0.AutoCol[ADA_US (p, "Number of columns", 1, MPAGCOL)] =
  194. X      a2ocol (ap, S("Maximum number of output columns"));
  195. Xelse if (bStrEQ (S("AutoFile"), cp))
  196. X   param0.AutoFil = ms2bool (ap, cp);
  197. Xelse if (bStrEQ (S("AutoLandscape"), cp))
  198. X   param0.AutoLnd = a2ocol (ap, cp);
  199. Xelse if (bStrEQ (S("BodySize"), cp))
  200. X   param0.BodySiz = mra2bp (ap, cp, 1.0, 1000.0);
  201. Xelse if (bStrEQ (S("BottomMarginLandscape"), cp))
  202. X   param0.BMargL = mra2bp (ap, cp, 0.0, MM(100.0));
  203. Xelse if (bStrEQ (S("BottomMarginPortrait"), cp))
  204. X   param0.BMargP = mra2bp (ap, cp, 0.0, MM(100.0));
  205. Xelse if (bStrEQ (S("BottomSkip"), cp))
  206. X   param0.BSkip = mra2bp (ap, cp, 0.0, MM(100.0));
  207. Xelse if (bStrEQ (S("CommandFile"), cp))
  208. X   {
  209. X   if (bStrEQ (ap, S("-"))) readrc (stdin, sStdin); else readpth (ap);
  210. X   }
  211. Xelse if (bStrEQ (S("Columns"), cp))
  212. X   param0.Columns = ADA_US (ap, cp, 1, MPAGCOL);
  213. Xelse if (bStrEQ (S("ColumnSeparation"), cp))
  214. X   param0.ColSep = mra2bp (ap, cp, 0.0, MM(100.0));
  215. Xelse if (bStrEQ (S("Debug"), cp))
  216. X   Debug = ADA_INT (ap, cp, 0, 9);
  217. Xelse if (bStrEQ (S("EndControlD"), cp))
  218. X   EndCtlD = ms2bool (ap, cp);
  219. Xelse if (bStrEQ (S("FixedWidthBodyFont"), cp))
  220. X   param0.FWFont = mcpstr (ap);
  221. Xelse if (bStrEQ (S("File"), cp))
  222. X   {
  223. X   if (filp == &fil[MFILES + 1]) malf1 (eMFiles, MFILES);
  224. X   filp->filName = mcpstr (ap);
  225. X   filp->filPara = param0;
  226. X   ++filp;
  227. X   }
  228. Xelse if (bStrEQ (S("FixedWidth"), cp))
  229. X   param0.FixWid = ms2bool (ap, cp);
  230. Xelse if (bStrEQ (S("FoldFirst"), cp))
  231. X   param0.FoldFst = a2ocol (ap, cp);
  232. Xelse if (bStrEQ (S("FoldIndent"), cp))
  233. X   param0.FoldInd = mra2bp (ap, cp, 0.0, MM(100.0));
  234. Xelse if (bStrEQ (S("FoldRest"), cp))
  235. X   param0.FoldRst = a2ocol (ap, cp);
  236. Xelse if (bStrEQ (S("FooterFont"), cp))
  237. X   param0.FootFnt = mcpstr (ap);
  238. Xelse if (bStrEQ (S("FooterHeight"), cp))
  239. X   param0.FootHt = mra2bp (ap, cp, 0.0, 72.0);
  240. Xelse if (bStrEQ (S("Header"), cp))
  241. X   filp->filHdr = mcpstr (ap);
  242. Xelse if (bStrEQ (S("HeaderFont"), cp))
  243. X   param0.HeadFnt = mcpstr (ap);
  244. Xelse if (bStrEQ (S("HeaderHeight"), cp))
  245. X   param0.HeadHt = mra2bp (ap, cp, 0.0, 1000.0);
  246. Xelse if (bStrEQ (S("LandscapeRotation"), cp))
  247. X   {
  248. X   param0.LandRot = ADA_INT (ap, cp, -90, 90);
  249. X   if ((-90 != param0.LandRot) && (90 != param0.LandRot)) malf1 (eRot);
  250. X   }
  251. Xelse if (bStrEQ (S("LeftMarginLandscape"), cp))
  252. X   param0.LMargL = mra2bp (ap, cp, 0.0, MM(100.0));
  253. Xelse if (bStrEQ (S("LeftMarginPortrait"), cp))
  254. X   param0.LMargP = mra2bp (ap, cp, 0.0, MM(100.0));
  255. Xelse if (bStrEQ (S("LineNumberFont"), cp))
  256. X   param0.LNFnt = mcpstr (ap);
  257. Xelse if (bStrEQ (S("LineNumberHeight"), cp))
  258. X   param0.LNHt = mra2bp (ap, cp, 0.0, 72.0);
  259. Xelse if (bStrEQ (S("LineNumberMultiple"), cp))
  260. X   param0.LNMult = ADA_US (ap, cp, 0, 1000);
  261. Xelse if (bStrEQ (S("LineNumberWidth"), cp))
  262. X   param0.LNWid = mra2bp (ap, cp, 0.0, MM(100.0));
  263. Xelse if (NULBSTR != (p = prefix (S("Octet"), cp)))
  264. X   addso (p, ap);
  265. Xelse if (bStrEQ (S("PageHeight"), cp))
  266. X   param0.PageHt = mra2bp (ap, cp, MM(100.0), MM(1000.0));
  267. Xelse if (bStrEQ (S("PageWidth"), cp))
  268. X   param0.PageWid = mra2bp (ap, cp, MM(100.0), MM(1000.0));
  269. Xelse if (bStrEQ (S("PostScript"), cp))
  270. X   FPRINTF (psos, "%s\n", ap);
  271. Xelse if (bStrEQ (S("Reverse"), cp))
  272. X   Reverse = ms2bool (ap, cp);
  273. Xelse if (bStrEQ (S("RightMarginLandscape"), cp))
  274. X   param0.RMargL = mra2bp (ap, cp, 0.0, MM(100.0));
  275. Xelse if (bStrEQ (S("RightMarginPortrait"), cp))
  276. X   param0.RMargP = mra2bp (ap, cp, 0.0, MM(100.0));
  277. Xelse if (bStrEQ (S("Spacing"), cp))
  278. X   param0.Spacing = mra2d (ap, NULBSTR, TRUE, cp, 0.5, 10.0, (bStrT *) NULL);
  279. Xelse if (bStrEQ (S("SymbolFont"), cp))
  280. X   param0.SymbFnt = mcpstr (ap);
  281. Xelse if (bStrEQ (S("TabWidth"), cp))
  282. X   param0.TabWid = ADA_US (ap, cp, 1, 80);
  283. Xelse if (bStrEQ (S("TextVertical"), cp))
  284. X   param0.TxtVert = ms2bool (ap, cp);
  285. Xelse if (bStrEQ (S("TopMarginLandscape"), cp))
  286. X   param0.TMargL = mra2bp (ap, cp, 0.0, MM(100.0));
  287. Xelse if (bStrEQ (S("TopMarginPortrait"), cp))
  288. X   param0.TMargP = mra2bp (ap, cp, 0.0, MM(100.0));
  289. Xelse if (bStrEQ (S("TopSkip"), cp))
  290. X   param0.TSkip = mra2bp (ap, cp, 0.0, MM(100.0));
  291. Xelse if (NULBSTR != (p = prefix (S("Undefine"), cp)))
  292. X   undef (p, ap);
  293. Xelse if (bStrEQ (S("VariableWidthBodyFont"), cp))
  294. X   param0.VWFont = mcpstr (ap);
  295. Xelse if (bStrEQ (S("XAdjust"), cp))
  296. X   param0.XAdjust = mra2bp (ap, cp, MM(-50.0), MM(50.0));
  297. Xelse if (bStrEQ (S("YAdjust"), cp))
  298. X   param0.YAdjust = mra2bp (ap, cp, MM(-50.0), MM(50.0));
  299. Xelse malf1 (eCmd, fn, ln, cp, ap);
  300. X}
  301. X
  302. X/* cpStdin - copy standard input to temporary file */
  303. X
  304. XPRIVATE void cpStdin (fp)
  305. XR1 filT *fp; /* Points to data for file.*/
  306. X
  307. X/* Function:
  308. X *    This is the result of a "File -" command.  The standard input
  309. X *    must be copied to a temporary file because cz needs to read it
  310. X *    twice.  If there was no Header command, make the header
  311. X *    "Standard Input."
  312. X * Algorithm:
  313. X *    Make temporary file.  Open it for append.  Call mfcopy().
  314. X *    Close files.
  315. X * Returns:
  316. X *    
  317. X * Notes:
  318. X *    1) Don't exit on a read error, just write a warning.
  319. X */
  320. X{
  321. XR2 streamT tos; /* Temporary file output stream.*/
  322. Xstatic char  tfnb2[] = "/tmp/czsXXXXXX"; /* Temporary file name buffer.*/
  323. X
  324. Xif (NULBSTR == fp->filHdr) fp->filHdr = sStdin;
  325. Xfp->filName = (bStrT) mktemp (tfnb2);
  326. Xtos = mfopen (fp->filName, "w+");
  327. Xfp->filTmp = TRUE;
  328. Xmfcopy (stdin, 0, sStdin, tos, 1, fp->filName);
  329. Xif (fclose (stdin)) malf0 (eClose, sStdin);
  330. Xmfclose (tos, fp->filName);
  331. Xif (DB(D_FILE)) FPRINTF (stderr, "stdin -> %s\n", fp->filName);
  332. X}
  333. X
  334. X/* cvcol - try to output one page column */
  335. X
  336. XPRIVATE int cvcol (fp, pc, clm, moc)
  337. XR6 filT     *fp;  /* Points to data for file to convert.*/
  338. XR7 unsigned  pc;  /* Page column number.*/
  339. XR9 unsigned  clm; /* Max number of output lines in column.*/
  340. X   unsigned  moc; /* Max output column.*/
  341. X
  342. X/* Function:
  343. X *    Attempt to emit one output column.  The output goes to a temporary
  344. X *    file, so if it fails, because of line overflow, the caller can
  345. X *    fseek back to the beginning of the failed attempt.
  346. X * Algorithm:
  347. X *    Loop until failure or until a complete column is output.
  348. X *    Call cvline() to attempt to convert each line, and switch
  349. X *    on the return code.  On success, end of column, end of page,
  350. X *    end of file in middle of line, or success (folded line),
  351. X *    print the line, using the appropriate PostScript functions
  352. X *    at the beginning and end of the line.  One end of file at the
  353. X *    beginning of a line or line overflow,  don't print anything, just
  354. X *    return the appropriate code.
  355. X * Returns:
  356. X *    SUCCESS or R_* code.
  357. X * Notes:
  358. X *    1) Variable s is used for for loop control (when negative) and
  359. X *       as return code (when non-negative).  This is a common trick.
  360. X *    2) linNum is incremented at the *end* of an input line, so eln
  361. X *       is 1 + linNum for folded lines.
  362. X */
  363. X{
  364. XR8 unsigned cl = 1;  /* Output line number within column.*/
  365. XR5 unsigned eln;     /* Effective line number.*/
  366. XR4 boolT    p;       /* Print this output line.*/
  367. XR2 bStrT    pnb;     /* PostScript procedure for beginning of line.*/
  368. XR3 bStrT    pne;     /* PostScript procedure for end of line.*/
  369. XR1 int      s = -1;  /* Return code.*/
  370. X   char     lns[20]; /* Line number string.*/
  371. X
  372. XFPRINTF (psts, "(%u)%u %s\n", pc, pc, PCOLB);
  373. Xfor (; s < 0; ++cl)
  374. X   {
  375. X   outBufP = outBuf;
  376. X   p = FALSE;
  377. X   psLinL = 0;
  378. X   switch (s = cvline (fp, moc))
  379. X      {
  380. X      case SUCCESS:
  381. X      case R_COLE:
  382. X      case R_PAGEE:
  383. X      case R_EOFM:
  384. X         if (linCont)
  385. X            {
  386. X            pnb = PLLB;
  387. X            pne = PLLE;
  388. X            linCont = FALSE;
  389. X            }
  390. X         else
  391. X            {
  392. X            pnb = PSLB;
  393. X            pne = PSLE;
  394. X            }
  395. X         if ((SUCCESS == s) && (cl != clm)) s = -1;
  396. X         p = TRUE;
  397. X         break;
  398. X      case R_CONT:
  399. X         if (linCont)
  400. X            {
  401. X            pnb = PMLB;
  402. X            pne = PMLE;
  403. X            }
  404. X         else
  405. X            {
  406. X            pnb = PFLB;
  407. X            pne = PFLE;
  408. X            linCont = TRUE;
  409. X            }
  410. X         s = ((cl == clm) ? SUCCESS : -1);
  411. X         p = TRUE;
  412. X         break;
  413. X      case R_EOFB:
  414. X         if (1 != cl) s = R_EOFM;
  415. X         break;
  416. X      case R_OVFL:
  417. X         break;
  418. X      default:
  419. X         malf1 (eIntern, "cvcol", __LINE__);
  420. X         break;
  421. X      }
  422. X   if (p)
  423. X      {
  424. X      eln = linNum;
  425. X      if (linCont) ++eln;
  426. X      PSPUTC (EOS);
  427. X      if ((0 != fp->filPara.LNMult) &&
  428. X          ((0 == (eln % fp->filPara.LNMult)) || (eln==lines)))
  429. X         SPRINTF (lns, "(%u)", eln);
  430. X      else
  431. X         STRCPY (lns, "()");
  432. X      FPRINTF (psts, "%s%u %s\n%s%s%u %s\n", lns, eln, pnb,
  433. X            outBuf, lns, eln, pne);
  434. X      }
  435. X   }
  436. XFPRINTF (psts, "(%u)%u %s\n", pc, pc, PCOLE);
  437. Xif (DB(D_COL)) FPRINTF (stderr, "cvcol (%u, %u, %u) = %d\n", pc, clm, moc, s);
  438. Xreturn (s);
  439. X}
  440. X
  441. X/* cvfile - convert one file into PostScript */
  442. X
  443. XPRIVATE void cvfile (fp)
  444. XR2 filT *fp; /* Points to data for file to convert.*/
  445. X
  446. X/* Function:
  447. X *    Convert the file to PostScript.
  448. X * Algorithm:
  449. X *    If the file is standard input, copy it to a temporary file.
  450. X *    Call doTop() to generate the output that is the same for every page.
  451. X *    Open the file and call preScan() to compute the starting number
  452. X *    of page columns for each page (pc0), and starting orientation (por0).
  453. X *    preScan also counts input lines.  Open a temporary output file.
  454. X *    The outer (mf) loop is executed once for each page.
  455. X *    The inner (mp) loop is executed once for each page attempt.
  456. X *    Start with pc0 and por0.  Compute the maximum allowed output
  457. X *    columns for this page attempt (moc) from pc, por, and the
  458. X *    AutoFile, AutoLandscape, and AutoColumn data.  Call cvpage()
  459. X *    to make the try.  On overflow, first try decreasing pc.  If pc
  460. X *    is 1, try going to landscape.  Seek back to the beginning of the
  461. X *    page and try again.  At the end of the outer loop, step through
  462. X *    each page and call putPage() to write it for real.
  463. X * Notes:
  464. X *    
  465. X */
  466. X{
  467. XR9     streamT   f;                   /* Input stream.*/
  468. XR10    long      isp;                 /* Offset in input stream.*/
  469. XR8     boolT     mf;                  /* More of file to read.*/
  470. XR3     unsigned  moc;                 /* Max number of output columns to try.*/
  471. XR1     boolT     mp;                  /* More of page to convert.*/
  472. X       ncStatT   ncs;                 /* Save nc state at beginning of page.*/
  473. XR11    long      osp;                 /* Offset in output stream.*/
  474. XR14    unsigned  pages;               /* Pages of output for this file.*/
  475. XR5     unsigned  pc;                  /* Current number of page columns.*/
  476. X       unsigned  pc0;                 /* Initial number of page columns.*/
  477. XR4     boolT     por;                 /* Current page in portrait mode.*/
  478. X       boolT     por0;                /* Initially portrait mode.*/
  479. XR7     unsigned  pn;                  /* Page number.*/
  480. XR6     int       s;                   /* Return code.*/
  481. XR12    unsigned  sln;                 /* Save line number.*/
  482. X       pageT     pageBy[MPAGES + 2];  /* Offset in psts of each page.*/
  483. XR13    pageT    *pp;                  /* Steps through pageBy[].*/
  484. Xstatic char      tfnb1[] = "/tmp/czpXXXXXX"; /* Temporary file name buffer.*/
  485. X
  486. Xif (DB(D_FILE)) FPRINTF (stderr, "cvfile %s\n", fp->filName);
  487. Xif (bStrEQ (S("-"), fp->filName)) cpStdin (fp);
  488. Xif (!doTop (fp)) return;
  489. Xf = fopen (fp->filName, "r");
  490. Xif (NULSTRM == f)
  491. X   {
  492. X   malf0 (eOpen, fp->filName);
  493. X   return;
  494. X   }
  495. XpreScan (fp, f, &pc0, &por0);
  496. Xif (0 == pc0)
  497. X   {
  498. X   malf0 (eEmpty, fp->filName);
  499. X   if (fclose (f)) malf0 (eClose, fp->filName);
  500. X   if (fp->filTmp)
  501. X      {
  502. X      if (unlink (fp->filName)) malf0 (eUnlink, fp->filName);
  503. X      }
  504. X   return;
  505. X   }
  506. Xif (NULCSTR == pstfn) pstfn = mktemp (tfnb1);
  507. Xpsts = mfopen (pstfn, "w+");
  508. Xnc = nc0;
  509. Xnc.ncIStrm = f;
  510. XlinNum = 0;
  511. Xpn = 0;
  512. Xpp = &pageBy[1];
  513. Xfor (mf = TRUE; mf;)
  514. X   {
  515. X   ++pn;
  516. X   pc = pc0;
  517. X   por = por0;
  518. X   isp = ftell (f);
  519. X   ncs = nc;
  520. X   osp = ftell (psts);
  521. X   sln = linNum;
  522. X   for (mp = TRUE; mp;)
  523. X      {
  524. X      if (fp->filPara.AutoFil)
  525. X         moc = MOCOL;
  526. X      else if (por && (1 == pc))
  527. X         moc = fp->filPara.AutoLnd;
  528. X      else if (1 != pc)
  529. X         moc = fp->filPara.AutoCol[pc];
  530. X      else
  531. X         moc = MOCOL;
  532. X      s = cvpage (fp, pc, por, moc);
  533. X      switch (s)
  534. X         {
  535. X         case R_EOFB:
  536. X            --pn;
  537. X            /* Falls through.*/
  538. X         case R_EOFM:
  539. X            mf = FALSE;
  540. X            /* Falls through.*/
  541. X         case SUCCESS:
  542. X         case R_PAGEE:
  543. X            mp = FALSE;
  544. X            break;
  545. X         case R_OVFL:
  546. X            if (por && (1 == pc))
  547. X               por = FALSE;
  548. X            else if (1 != pc)
  549. X               --pc;
  550. X            else
  551. X               malf1 (eIntern, "cvfile", __LINE__);
  552. X            mfseek (f, isp, 0, fp->filName);
  553. X            mfflush (psts, pstfn);
  554. X            mfseek (psts, osp, 0, pstfn);
  555. X            linNum = sln;
  556. X            nc = ncs;
  557. X            break;
  558. X         default:
  559. X            malf1 (eIntern, "cvfile", __LINE__);
  560. X            break;
  561. X         }
  562. X      }
  563. X   if (pn > MPAGES) malf1 (eMPages, fp->filName, MPAGES);
  564. X   if (R_EOFB != s)
  565. X      {
  566. X      mfflush (psts, pstfn);
  567. X      pp->pgPos = osp;
  568. X      pp->pgCols = pc;
  569. X      pp->pgPor = por;
  570. X      ++pp;
  571. X      if (DB(D_PAGE))
  572. X         FPRINTF (stderr, "page %u: %u cols %s\n", pn,
  573. X                  pc, por ? "portrait" : "landscape");
  574. X      }
  575. X   }
  576. Xif (ferror (f)) malf0 (eReadL, fp->filName, linNum);
  577. Xif (fclose (f)) malf0 (eClose, fp->filName);
  578. Xif (fp->filTmp)
  579. X   {
  580. X   if (unlink (fp->filName)) malf0 (eUnlink, fp->filName);
  581. X   }
  582. Xpages = pn;
  583. Xif (Reverse)
  584. X   {
  585. X   pp->pgPos = ftell (psts);
  586. X   for (--pp; pp != pageBy; --pp)
  587. X      putPage (fp, pp, pn--, pages, pp[1].pgPos - pp->pgPos);
  588. X   }
  589. Xelse
  590. X   {
  591. X   pn = 1;
  592. X   pp->pgPos = ftell (psts);
  593. X   for (pp = &pageBy[1]; pn <= pages; ++pp)
  594. X      putPage (fp, pp, pn++, pages, pp[1].pgPos - pp->pgPos);
  595. X   }
  596. Xif (fclose (psts)) malf0 (eClose, pstfn);
  597. XtotPag += pages;
  598. X}
  599. X
  600. X/* cvline - Try to convert one output line to PostScript */
  601. X
  602. XPRIVATE int cvline (fp, moc)
  603. XR9 filT     *fp;  /* Points to data for file to convert.*/
  604. XR8 unsigned  moc; /* Max output column.*/
  605. X
  606. X/* Function:
  607. X *    Attempt to convert one output line.  The output goes into a buffer;
  608. X *    it is not written onto the temporary file here.  This is because
  609. X *    the output must be preceded by a call to the appropriate PostScript
  610. X *    procedure, but which one is appropriate depends on whether the line
  611. X *    is folded.
  612. X * Algorithm:
  613. X *    Loop.  Call nextc() to get next input character and convert it
  614. X *    to nextc() output form, which is an array of unsigned shorts.
  615. X *    Elements less than 256 are literal bytes to be output; other
  616. X *    elements are from the T_* codes, with a bias of 256.
  617. X *    (T_END + 256) marks the end of the array.
  618. X *
  619. X *    Set endF if this character ends the line in some way.
  620. X *    Set tabF is this character is a tab.  Compute the number of
  621. X *    spaces.  (The -1 is because nextc() has already incremented
  622. X *    nc.ncICol and oCol.)  Check for output column overflow and folding.
  623. X *    Step through each element in the array.  Put literal bytes into
  624. X *    the buffer and switch on the T_* codes.  If a PostScript line
  625. X *    could become longer than MPSLINE characters, force the end of a
  626. X *    string.
  627. X * Returns:
  628. X *    Return code.
  629. X * Notes:
  630. X *    1) The ENDSTR macro assumes that PSPUTC is one character.
  631. X *    2) Warning messages for undefined characters have already
  632. X *       been printed in the preScan() pass.
  633. X */
  634. X{
  635. X/* If outputting a PostScript string, end it:*/
  636. X#define ENDSTR {if(ins){PSPUTC(')');PSPUTC(*PSHOW);PSPUTC('\n');ins=FALSE;}}
  637. XR2  ushrtT   *pp;          /* Returned by nextc().*/
  638. XR1  ushrtT   *pp2;         /* Steps through pp[].*/
  639. XR3  boolT     endF;        /* T_{LINE,COLE,PAGEE,EOF} in pp[].*/
  640. XR4  boolT     tabF;        /* T_TAB in pp[].*/
  641. XR5  boolT     ins = FALSE; /* Flag set when PS string being output.*/
  642. XR6  int       s = -1;      /* Loop control and return code.*/
  643. XR7  unsigned  spcs;        /* Tab expands into this many spaces.*/
  644. XR10 int       i;           /* Count octets.*/
  645. X
  646. XoCol = 0;
  647. Xwhile (s < 0)
  648. X   {
  649. X   pp = nextc();
  650. X   endF = FALSE;
  651. X   tabF = FALSE;
  652. X   for (pp2 = pp; (T_END + 256) != *pp2; ++pp2)
  653. X      {
  654. X      if (((T_LINEE + 256) == *pp2) || ((T_COLE + 256) == *pp2) ||
  655. X          ((T_PAGEE + 256) == *pp2) || ((T_EOF + 256) == *pp2))
  656. X         endF = TRUE;
  657. X      else if ((T_TAB + 256) == *pp2)
  658. X         tabF = TRUE;
  659. X      }
  660. X   if (!tabF)
  661. X      spcs = 1;
  662. X   else
  663. X      {
  664. X      spcs = fp->filPara.TabWid - ((nc.ncICol - 1) % fp->filPara.TabWid);
  665. X      nc.ncICol += spcs - 1;
  666. X      oCol += spcs - 1;
  667. X      }
  668. X   if (!endF)
  669. X      {
  670. X      if (oCol >= moc)
  671. X         s = R_OVFL;
  672. X      else if (oCol >= (linCont ? fp->filPara.FoldRst : fp->filPara.FoldFst))
  673. X         {
  674. X         if (nc.ncUn) malf1 (eIntern, "cvline", __LINE__);
  675. X         nc.ncUn = TRUE;
  676. X         nc.ncICol -= spcs;
  677. X         s = R_CONT;
  678. X         }
  679. X      }
  680. X   if (s < 0)
  681. X      {
  682. X      do
  683. X         {
  684. X         if (*pp <= 256)
  685. X            PSPUTC (*pp);
  686. X         else
  687. X            {
  688. X            switch (*pp - 256)
  689. X               {
  690. X               case T_UNDEF:
  691. X                  ENDSTR;
  692. X                  PSPUTC ('(');
  693. X                  if (fp->filPara.FixWid)
  694. X                     SPRINTF (outBufP, "%02X", nc.ncOb[nc.ncN - 1]);
  695. X                  else
  696. X                     {
  697. X                     SPRINTF (outBufP, "%o", nc.ncOb[0]);
  698. X                     for (i = 1; i != nc.ncN; ++i)
  699. X                        {
  700. X                        outBufP = strend (outBufP);
  701. X                        SPRINTF (outBufP, " %o", nc.ncOb[i]);
  702. X                        }
  703. X                     }
  704. X                  outBufP = strend (outBufP);
  705. X                  SPRINTF (outBufP, ")%s", PUNDEF);
  706. X                  outBufP = strend (outBufP);
  707. X                  PSPUTC ('\n');
  708. X                  break;
  709. X               case T_TAB:
  710. X                  if (!ins)
  711. X                     {
  712. X                     PSPUTC ('(');
  713. X                     ins = TRUE;
  714. X                     }
  715. X                  while (spcs--)
  716. X                     PSPUTC (' ');
  717. X                  break;
  718. X               case T_STRB:
  719. X                  if (!ins)
  720. X                     {
  721. X                     PSPUTC ('(');
  722. X                     ins = TRUE;
  723. X                     }
  724. X                  break;
  725. X               case T_STRE:
  726. X                  ENDSTR;
  727. X                  break;
  728. X               case T_LINEE:
  729. X                  ++linNum;
  730. X                  nc.ncICol = 0;
  731. X                  s = SUCCESS;
  732. X                  break;
  733. X               case T_COLE:
  734. X                  s = R_COLE;
  735. X                  break;
  736. X               case T_PAGEE:
  737. X                  s = R_PAGEE;
  738. X                  break;
  739. X               case T_EOF:
  740. X                  s = ((0 == oCol) ? R_EOFB : R_EOFM);
  741. X                  break;
  742. X               }
  743. X            }
  744. X         }
  745. X      while ((T_END + 256) != *++pp);
  746. X      }
  747. X   if (!ins)
  748. X      PSPUTC ('\n');
  749. X   else if (psLinL > (MPSLINE - MMULOCT * MPSSTR - 1))
  750. X      ENDSTR;
  751. X   }
  752. XENDSTR;
  753. Xif (DB(D_LINE)) FPRINTF (stderr, "cvline %u = %d\n", linNum, s);
  754. Xreturn (s);
  755. X}
  756. X
  757. X/* cvpage - try to convert one page to PostScript */
  758. X
  759. XPRIVATE int cvpage (fp, pc, por, moc)
  760. XR4 filT     *fp;  /* Points to data for file to convert.*/
  761. XR3 unsigned  pc;  /* Page columns to try.*/
  762. X   boolT     por; /* Portrait mode.*/
  763. XR6 unsigned  moc; /* Max input column.*/
  764. X
  765. X/* Function:
  766. X *    Try to convert one page.
  767. X * Algorithm:
  768. X *    Compute clm, the maximum number of output lines that will fit
  769. X *    in one output column.  This has to be recomputed for each page
  770. X *    attempt because pc and por can be different.  Loop over the
  771. X *    page columns.  Call cvcol() to try to convert one column, and
  772. X *    switch on the return code.
  773. X * Returns:
  774. X *    Return code.
  775. X * Notes:
  776. X *    
  777. X */
  778. X{
  779. X   double    bodHt;  /* Body height.*/
  780. XR2 unsigned  c = 1;  /* Current page column.*/
  781. XR5 unsigned  clm;    /* Max number of output lines in a page column.*/
  782. XR7 paramT   *p = &fp->filPara;
  783. X   double    leading = p->BodySiz * p->Spacing; /* Space between lines.*/
  784. XR1 int       s;      /* Return code.*/
  785. X   double    yHead;  /* Y coordinate of header baseline.*/
  786. X
  787. Xif (por)
  788. X   {
  789. X   yHead = p->PageHt - p->TMargP - p->HeadHt;
  790. X   if (yHead <= 0.0) malf1 (eBigHd, p->TMargP + p->HeadHt, p->PageHt);
  791. X   bodHt = yHead - p->TSkip - p->BSkip - p->FootHt - p->BMargL;
  792. X   }
  793. Xelse
  794. X   {
  795. X   yHead = p->PageWid - p->TMargL - p->HeadHt;
  796. X   if (yHead <= 0.0) malf1 (eBigHd, p->TMargL + p->HeadHt, p->PageWid);
  797. X   bodHt = yHead - p->TSkip - p->BSkip - p->FootHt - p->BMargP;
  798. X   }
  799. Xif (bodHt < leading) malf1 (eNoBod, bodHt, leading);
  800. Xclm = (unsigned)(bodHt / leading);
  801. Xfor (s = -1; s < 0; ++c)
  802. X   {
  803. X   switch (s = cvcol (fp, c, clm, moc))
  804. X      {
  805. X      case SUCCESS:
  806. X      case R_COLE:
  807. X         s = ((c == pc) ? SUCCESS : -1);
  808. X         break;   
  809. X      case R_EOFM:
  810. X      case R_PAGEE:
  811. X      case R_OVFL:
  812. X         break;
  813. X      case R_EOFB:
  814. X         if (1 != c) s = R_EOFM;
  815. X         break;
  816. X      default:
  817. X         malf1 (eIntern, "cvpage", __LINE__);
  818. X         break;
  819. X      }
  820. X   }
  821. Xif (DB(D_PAGEA))
  822. X   FPRINTF (stderr, "cvpage (%u, %s, %u) = %d\n", pc,
  823. X            por ? "portrait" : "landscape", moc, s);
  824. Xreturn (s);
  825. X}
  826. X
  827. X/* docFnts - output %%DocumentFonts: comment */
  828. X
  829. XPRIVATE void docFnts()
  830. X
  831. X/* Function:
  832. X *    Write the DocumentFonts structure comment that lists all fonts
  833. X *    used.  Get as many font names on a line as possible, without
  834. X *    exceeding MPSLINE.  Use the %%+ line continuation convention
  835. X *    if necessary.
  836. X * Algorithm:
  837. X *    Step through fonts[], write each font name, and keep track of
  838. X *    the output column.
  839. X * Returns:
  840. X *    
  841. X * Notes:
  842. X *    
  843. X */
  844. X{
  845. XR2     unsigned  c;  /* Output column.*/
  846. XR1     fontT    *fp; /* Steps through fonts[].*/
  847. XR3     unsigned  l;  /* Length of font name and leading space.*/
  848. Xstatic char      df[] = "%%DocumentFonts:";
  849. X
  850. Xc = strlen (df);
  851. XFPUTS (df, psos);
  852. Xfor (fp = fonts; fp != fontP; ++fp)
  853. X   {
  854. X   l = 1 + strlen (fp->fntName);
  855. X   if ((c + l) >= MPSLINE)
  856. X      {
  857. X      FPUTS ("\n%%+", psos);
  858. X      c = 0;
  859. X      }
  860. X   PUTC (' ', psos);
  861. X   FPUTS (fp->fntName, psos);
  862. X   c += l;
  863. X   }
  864. XPUTC ('\n', psos);
  865. X}
  866. X
  867. X/* doTop - set up topBuf[] for a new file */
  868. X
  869. XPRIVATE boolT doTop (fp)
  870. XR3 filT *fp; /* Points to data for file to convert.*/
  871. X
  872. X/* Function:
  873. X *    There is some repetitive stuff at the beginning of every page
  874. X *    that is the same for every file.  It's repeated so that every
  875. X *    PostScript page is independent of every other page.  This
  876. X *    allows page reversal, page selection, and parallel page interpretation.
  877. X *    This function generates the constant top-of-page stuff, and
  878. X *    places it in the topBuf[] buffer.
  879. X * Algorithm:
  880. X *    Store the constant defs.  Call cvline() to store the header.
  881. X * Returns:
  882. X *    TRUE of success; FALSE on error.
  883. X * Notes:
  884. X *    
  885. X */
  886. X{
  887. XR2 paramT *p = &fp->filPara;
  888. XR1 bStrT   tp; /* Steps through topBuf[].*/
  889. X
  890. Xtp = topBuf;
  891. XSPRINTF (tp, "%s\n", PSAVE);
  892. Xtp = strend (tp);
  893. XSPRINTF (tp, "/%s /%sE %s\n", PFONT, p->FixWid ? p->FWFont : p->VWFont,
  894. X         PDEF);
  895. Xtp = strend (tp);
  896. XSPRINTF (tp, "/%s /%sE %s\n", FOOTFNT, p->FootFnt, PDEF);
  897. Xtp = strend (tp);
  898. XSPRINTF (tp, "/%s /%sE %s\n", HEADFNT, p->HeadFnt, PDEF);
  899. Xtp = strend (tp);
  900. XSPRINTF (tp, "/%s /%sE %s\n", PLNFNT, p->LNFnt, PDEF);
  901. Xtp = strend (tp);
  902. XSPRINTF (tp, "/%s /%s %s\n", SYMBFNT, p->SymbFnt, PDEF);
  903. Xtp = strend (tp);
  904. XSPRINTF (tp, "/%s %s %s\n", PFIXWID, p->FixWid ? "true" : "false", PDEF);
  905. XoutBufP = strend (tp);
  906. XoutBufE = &topBuf[MTOPBUF];
  907. XputDimO (BODYSIZ, p->BodySiz);
  908. XputDimO (PFOOTHT, p->FootHt);
  909. XputDimO (PHEADHT, p->HeadHt);
  910. XputDimO (LEADING, p->BodySiz * p->Spacing);
  911. XputDimO (PLNHT,   p->LNHt);
  912. XputDimO (PLNWID,  p->LNWid);
  913. XputDimO (XADJUST, p->XAdjust);
  914. XputDimO (YADJUST, p->YAdjust);
  915. XSPRINTF (outBufP, "/%s", PHEADER);
  916. XoutBufP = strend (outBufP);
  917. XPSPUTC ('\n');
  918. XPSPUTC ('{');
  919. XPSPUTC ('\n');
  920. Xnc = nc0;
  921. Xnc.ncFP = fp;
  922. Xif (NULBSTR == fp->filHdr) fp->filHdr = fp->filName;
  923. Xnc.ncStr = fp->filHdr;
  924. Xswitch (cvline (fp, MOCOL))
  925. X   {
  926. X   case R_EOFB:
  927. X   case R_EOFM:
  928. X      break; 
  929. X   case SUCCESS:
  930. X      malf0 (eHdrEnd, "line", fp->filName, fp->filHdr);
  931. X      return (FALSE);
  932. X   case R_COLE:
  933. X      malf0 (eHdrEnd, "column", fp->filName, fp->filHdr);
  934. X      return (FALSE);
  935. X   case R_PAGEE:
  936. X      malf0 (eHdrEnd, "page", fp->filName, fp->filHdr);
  937. X      return (FALSE);
  938. X   default:
  939. X      malf1 (eIntern, "cvfile", __LINE__);
  940. X      break;
  941. X   }
  942. XPSPUTC ('}');
  943. XSTRCPY (outBufP, PDEF);
  944. XoutBufP = strend (outBufP);
  945. XPSPUTC ('\n');
  946. XPSPUTC (EOS);
  947. Xnc = nc0;
  948. Xreturn (TRUE);
  949. X}
  950. X
  951. X/* headCom - output PostScript structure header comments */
  952. X
  953. XPRIVATE void headCom()
  954. X
  955. X/* Function:
  956. X *    Output the structure comments at the beginning of the PostScript
  957. X *    output.
  958. X * Algorithm:
  959. X *    
  960. X * Returns:
  961. X *    
  962. X * Notes:
  963. X *    1) The %%For: line is entirely optional.  If your system
  964. X *       has any trouble with the code to generate it, you can
  965. X *       safely comment it out.
  966. X */
  967. X{
  968. XR1     struct tm *tmp;       /* Returned by localtime().*/
  969. X       long       ut;        /* Current system time.*/
  970. X       byteT      fnb[1024]; /* Store user's full name here.*/
  971. Xextern long       time();    /* (3C).*/
  972. X
  973. XFPUTS ("%!PS-Adobe-2.1\n", psos);
  974. XFPRINTF (psos, "%%%%Creator: cz%d.%d\n", FRZ_MAJ, FRZ_MIN);
  975. Xut = time ((long *) NULL);
  976. Xtmp = localtime (&ut);
  977. XFPRINTF (psos, "%%%%CreationDate: %d-%02d-%02d %02d:%02d:%02d\n",
  978. X         1900 + tmp->tm_year, 1 + tmp->tm_mon, tmp->tm_mday,
  979. X         tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  980. Xif (NULBSTR != userfn (fnb)) FPRINTF (psos, "%%%%For: %s\n", fnb);
  981. XFPUTS ("%%Pages: (atend)\n", psos);
  982. XFPUTS ("%%DocumentFonts: (atend)\n", psos);
  983. X}
  984. X
  985. X/* init - initialize at start of execution */
  986. X
  987. XPRIVATE void init()
  988. X
  989. X/* Function:
  990. X *    Initialize some things.
  991. X * Algorithm:
  992. X *    
  993. X * Returns:
  994. X *    
  995. X * Notes:
  996. X *    1) The umask setting will make the temporary files unreadable by
  997. X *       others than the creator, for security.
  998. X */
  999. X{
  1000. XR1     bStrT   bp1;     /* Steps through ncMap[].*/
  1001. XR2     bStrT   bp2;     /* End of ncMap[].*/
  1002. XR5     int     i;       /* Loop counter.*/
  1003. XR3     ushrtT *up1;     /* Steps through AutoCol[].*/
  1004. XR4     ushrtT *up2;     /* End of AutoCol[].*/
  1005. Xextern int     umask(); /* (2).*/
  1006. X
  1007. X(void) umask (0077);
  1008. Xnc0.ncStr = NULBSTR;
  1009. Xbp1 = ncMap;
  1010. Xbp2 = &ncMap[256];
  1011. Xwhile (bp1 != bp2)
  1012. X   *bp1++ = T_RES;
  1013. XncMap[E_STRB]  = T_STRB;
  1014. XncMap[E_STRE]  = T_STRE;
  1015. XncMap[E_COM]   = T_COM;
  1016. XncMap[E_EESC]  = T_EESC;
  1017. XncMap[E_COLE]  = T_COLE;
  1018. XncMap[E_LINEE] = T_LINEE;
  1019. XncMap[E_PAGEE] = T_PAGEE;
  1020. XncMap[E_TAB]   = T_TAB;
  1021. Xup1 = param0.AutoCol;
  1022. Xup2 = up1 + MPAGCOL + 1;
  1023. Xwhile (up1 != up2)
  1024. X   *up1++ = MOCOL;
  1025. Xparam0.AutoLnd = MOCOL;
  1026. Xfor (i = 1; MSTATE != i; ++i)
  1027. X   states[i] = (stateT *) NULL;
  1028. X#include "cz0-init.h"
  1029. X}
  1030. X
  1031. X/* mpsputc - handle output buffer overflow */
  1032. X
  1033. XPRIVATE void mpsputc ()
  1034. X
  1035. X/* Function:
  1036. X *    The buffer in which PSPUTC stores bytes has overflowed.
  1037. X      Write an error message.
  1038. X * Algorithm:
  1039. X *    Figure out which buffer and call malf1().
  1040. X * Returns:
  1041. X *    No return.
  1042. X * Notes:
  1043. X *    
  1044. X */
  1045. X{
  1046. Xif (&outBuf[MOUTBUF] == outBufE)
  1047. X   malf1 (ePSPutC, "outBuf", MOUTBUF);
  1048. Xelse if (&topBuf[MTOPBUF] == outBufE)
  1049. X   malf1 (ePSPutC, "topBuf", MTOPBUF);
  1050. Xelse
  1051. X   malf1 (eIntern, "mpsputc", __LINE__);
  1052. X}
  1053. X
  1054. X/* mra2bp - convert string to typographical units and check for errors */
  1055. X
  1056. XPRIVATE double mra2bp (s, n, l, h)
  1057. XR3 bStrT  s; /* Input string.*/
  1058. X   bStrT  n; /* Name of field, for error messages.*/
  1059. X   double l; /* Lower bound.*/
  1060. X   double h; /* Upper bound.*/
  1061. X
  1062. X/* Function:
  1063. X *    String s is supposed to be a real numeric literal followed by a
  1064. X *    two-letter units abbreviation.  Convert it to big points. 
  1065. X * Algorithm:
  1066. X *    Linear search on units, then call mra2d().
  1067. X * Returns:
  1068. X *    PostScript internal units.
  1069. X * Notes:
  1070. X *    1) Maybe I should use perfect hashing on the units?
  1071. X *    2) For now, loose syntax is allowed, e.g. 0bp.  But this is not
  1072. X *       documented, so I can tighten up whenever I want.
  1073. X */
  1074. X{
  1075. X   double sf; /* Scaling factor.*/
  1076. XR2 int    ls; /* Length of input string.*/
  1077. XR1 bStrT  p;  /* Should point to units.*/
  1078. X
  1079. Xif (DB(D_PSC)) FPRINTF (stderr, "mra2bp (%s, %s, %G, %G)\n", s, n, l, h);
  1080. Xls = strlen (s);
  1081. Xif (ls < 3) malf1 ("%s [%s]: Bad format", n, s);
  1082. Xp = &s[ls - 2];
  1083. Xif      (bStrEQ (S("bp"), p)) sf = 1.0;
  1084. Xelse if (bStrEQ (S("cc"), p)) sf = CF_CC;
  1085. Xelse if (bStrEQ (S("cm"), p)) sf = CF_CM;
  1086. Xelse if (bStrEQ (S("dd"), p)) sf = CF_DD;
  1087. Xelse if (bStrEQ (S("in"), p)) sf = CF_IN;
  1088. Xelse if (bStrEQ (S("mm"), p)) sf = CF_MM;
  1089. Xelse if (bStrEQ (S("pc"), p)) sf = CF_PC;
  1090. Xelse if (bStrEQ (S("pt"), p)) sf = CF_PT;
  1091. Xelse malf1 (eUnits, n, s, p);
  1092. Xreturn (sf * mra2d (s, p, TRUE, n, l, h, (bStrT *) NULL));
  1093. X}
  1094. X
  1095. X/* ms2bool - convert string to Boolean and handle errors */
  1096. X
  1097. XPRIVATE boolT ms2bool (s, fn)
  1098. XR1 bStrT s;  /* Input string.*/
  1099. X   bStrT fn; /* Field name.*/
  1100. X
  1101. X/* Function:
  1102. X *    Convert string representations of Booleans to internal representation.
  1103. X * Algorithm:
  1104. X *    Linear search.
  1105. X * Returns:
  1106. X *    TRUE or FALSE.  No return on error.
  1107. X * Notes:
  1108. X *    1) Case is significant.
  1109. X */
  1110. X{
  1111. Xif (bStrEQ (S("false"), s)) return (FALSE);
  1112. Xelse if (bStrEQ (S("true"), s)) return (TRUE);
  1113. Xelse malf1 ("%s [%s] neither false nor true", s, fn);
  1114. X/*NOTREACHED*/
  1115. X}
  1116. X
  1117. X/* nextc - get next input character */
  1118. X
  1119. XPRIVATE ushrtT *nextc()
  1120. X
  1121. X/* Function:
  1122. X *    Convert one input character to output format.  The input character
  1123. X *    can come from a stream or a string (for headers).  A character
  1124. X *    can be up to MMULOCT bytes.  Output format is an array of unsigned
  1125. X *    shorts.  Elements in the range [0, 255] are bytes to be output literally.
  1126. X *    Higher elements are one of the T_* codes biased by 256.
  1127. X *    (T_END + 256) marks the end of the array.
  1128. X * Algorithm:
  1129. X *    If previous result was pushed back by line folding, unpush it and return.
  1130. X *    Otherwise, start in state 0 and loop.  Get one byte from the string
  1131. X *    or stream.  Handle end of string/file.  Get the state-octet entry.
  1132. X *    Step through the PostScript.  Copy ordinary characters to the return
  1133. X *    buffer, but switch on escapes.
  1134. X * Returns:
  1135. X *    A pointer to the array.
  1136. X * Notes:
  1137. X *    
  1138. X */
  1139. X{
  1140. XR7 stateT   *sp;  /* Points to current stateT.*/
  1141. XR4 soT      *sop; /* Points to current state-octet pair.*/
  1142. XR6 boolT     m;   /* More to do.*/
  1143. XR5 unsigned  st;  /* State.*/
  1144. XR3 ushrtT   *rbp; /* Steps through return buffer.*/
  1145. XR9 bStrT     obp; /* Steps through octet buffer.*/
  1146. XR8 rcharT    o;   /* Current input octet.*/
  1147. XR1 unsigned  p;   /* Current result byte.*/
  1148. XR2 bStrT     psp; /* Steps through PostScript for each state-octet pair.*/
  1149. X
  1150. Xif (nc.ncUn)
  1151. X   {
  1152. X   nc.ncUn = FALSE;
  1153. X   return (nc.ncRb);
  1154. X   }
  1155. Xst = 0;
  1156. Xobp = nc.ncOb;
  1157. Xrbp = nc.ncRb;
  1158. Xfor (m = TRUE; m;)
  1159. X   {
  1160. X   if (NULBSTR != nc.ncStr)
  1161. X      {
  1162. X      o = B(*nc.ncStr);
  1163. X      ++nc.ncStr;
  1164. X      if (EOS == o)
  1165. X         {
  1166. X         if (0 != st)
  1167. X            {
  1168. X            malf0 (eEOSSt, st, nc.ncFP->filHdr);
  1169. X            st = 0;
  1170. X            }
  1171. X         o = EOF;
  1172. X         }
  1173. X      }
  1174. X   else
  1175. X      {
  1176. X      o = getc (nc.ncIStrm);
  1177. X      if (EOF == o)
  1178. X         {
  1179. X         if (ferror (nc.ncIStrm)) malf0 (eRead, nc.ncFP->filName);
  1180. X         if (0 != st)
  1181. X            {
  1182. X            malf0 (eEOFSt, nc.ncFP->filName, st);
  1183. X            st = 0;
  1184. X            }
  1185. X         }
  1186. X      }
  1187. X   if (EOF == o)
  1188. X      {
  1189. X      *rbp++ = T_EOF + 256;
  1190. X      m = FALSE;
  1191. X      }
  1192. X   else
  1193. X      {
  1194. X      if ((o < 0) || (o > 255)) malf1 (eIntern, "nextc", __LINE__);
  1195. X      *obp++ = o;
  1196. X      if (0 == st)
  1197. X         {
  1198. X         ++nc.ncICol;
  1199. X         ++oCol;
  1200. X         }
  1201. X      p = 0;
  1202. X      sp = states[st];
  1203. X      if (((stateT *) NULL) == sp)
  1204. X         {
  1205. X         if (DB(D_OCT)) FPRINTF (stderr, "State %u undefined\n", st);
  1206. X         p = T_UNDEF + 256;
  1207. X         }
  1208. X      else
  1209. X         {
  1210. X         sop = ((soT *) sp) + o;
  1211. X         psp = sop->so_ps;
  1212. X         if (DB(D_OCT))
  1213. X            FPRINTF (stderr, "State %u Octet %c 8#%o# (%s%c%c%u)\n",
  1214. X                     st, o, o, psp, E_ESC, E_NEXTS, sop->so_nxt);
  1215. X         if (NULBSTR == psp) p = T_UNDEF + 256;
  1216. X         }
  1217. X      if ((T_UNDEF + 256) == p)
  1218. X         {
  1219. X         rbp = nc.ncRb;
  1220. X         *rbp++ = p;
  1221. X         st = 0;
  1222. X         }
  1223. X      else
  1224. X         {
  1225. X         for (; EOS != (p = B(*psp)); ++psp)
  1226. X            {
  1227. X            if (E_ESC != p)
  1228. X               *rbp++ = p;
  1229. X            else
  1230. X               {
  1231. X               ++psp;
  1232. X               p = ncMap[B(*psp)];
  1233. X               switch (p)
  1234. X                  {
  1235. X                  case T_RES: /* Can't happen.*/
  1236. X                     malf1 (eMap, E_ESC, *psp, *psp, st, o, o);
  1237. X                     break;
  1238. X                  case T_COM:
  1239. X                     *rbp++ = COMMENT;
  1240. X                     break;
  1241. X                  case T_EESC:
  1242. X                     *rbp++ = E_ESC;
  1243. X                     break;
  1244. X                  default:
  1245. X                     *rbp++ = p + 256;
  1246. X                     break;
  1247. X                  }
  1248. X               }
  1249. X            }
  1250. X         st = sop -> so_nxt;
  1251. X         }
  1252. X      }
  1253. X   if (0 == st) m = FALSE;
  1254. X   }
  1255. X*rbp = T_END + 256;
  1256. Xnc.ncN = obp - nc.ncOb;
  1257. Xif (DB(D_PSC))
  1258. X   {
  1259. X   for (rbp = nc.ncRb; (T_END + 256) != *rbp; ++rbp)
  1260. X      {
  1261. X      if (*rbp < 256)
  1262. X         PUTC (*rbp, stderr);
  1263. X      else
  1264. X         {
  1265. X         switch (*rbp - 256)
  1266. X            {
  1267. X            case T_UNDEF:
  1268. X               FPRINTF (stderr, "%cU", E_ESC);
  1269. X               break;
  1270. X            case T_STRB:
  1271. X               FPRINTF (stderr, "%c%c", E_ESC, E_STRB);
  1272. X               break;
  1273. X            case T_STRE:
  1274. X               FPRINTF (stderr, "%c%c", E_ESC, E_STRE);
  1275. X               break;
  1276. X            case T_TAB:
  1277. X               FPRINTF (stderr, "%c%c(%u)", E_ESC, E_TAB, nc.ncICol);
  1278. X               break;
  1279. X            case T_COLE:
  1280. X               FPRINTF (stderr, "%c%c", E_ESC, E_COLE);
  1281. X               break;
  1282. X            case T_LINEE:
  1283. X               FPRINTF (stderr, "%c%c", E_ESC, E_LINEE);
  1284. X               break;
  1285. X            case T_PAGEE:
  1286. X               FPRINTF (stderr, "%c%c", E_ESC, E_PAGEE);
  1287. X               break;
  1288. X            case T_EOF:
  1289. X               FPRINTF (stderr, "%cE", E_ESC);
  1290. X               break;
  1291. X            default:
  1292. X               malf1 (eIntern, "nextc", __LINE__);
  1293. X               break;
  1294. X            }
  1295. X         }
  1296. X      }
  1297. X   PUTC ('\n', stderr);
  1298. X   }
  1299. Xreturn (nc.ncRb);
  1300. X}
  1301. X
  1302. X/* preScan - find widest line in input file, and count lines */
  1303. X
  1304. XPRIVATE void preScan (fp, f, pcp, porp)
  1305. X   filT     *fp;   /* Points to data for file to convert.*/
  1306. XR8 streamT   f;    /* Input stream.*/
  1307. X   unsigned *pcp;  /* Store initial number of page columns here.*/
  1308. X   boolT    *porp; /* Store initial orientation here.*/
  1309. X
  1310. X/* Function:
  1311. X *    If AutoColumn or AutoLandscape are being done on a whole-file
  1312. X *    basis (AutoFile true), then we need to know the widest line in
  1313. X *    the file.  Also, we need to know the number of lines in the file
  1314. X *    so we can always output the line number of the last one.
  1315. X *    This function reads through the entire file and then rewinds it
  1316. X *    for the conversion pass.
  1317. X * Algorithm:
  1318. X *    Loop through each input character.  Switch on T_* codes.
  1319. X *    Expand tabs.  On end of line set mc = max (mc, oCol).
  1320. X *    At the end of the loop, compute pc0 and por0.
  1321. X * Returns:
  1322. X *    Stores pc0 in *pcp and por0 in *porp.  pc0 is 0 for an empty file.
  1323. X * Notes:
  1324. X *    1) This pass could be avoided if AutoFile is false and line numbers
  1325. X *       are not being printed.
  1326. X */
  1327. X{
  1328. XR4 boolT     nl = TRUE; /* Start of new line.*/
  1329. XR5 unsigned  mc = 0;    /* Max input columns in file.*/
  1330. XR6 unsigned  mcl = 0;   /* Line number of (first) widest line in file.*/
  1331. XR2 paramT   *p = &fp->filPara;
  1332. XR7 unsigned  pc;        /* Initial page columns.*/
  1333. XR1 ushrtT   *pp;        /* Returned by nextc().*/
  1334. XR3 unsigned  spcs;      /* Tab expands into this many spaces.*/
  1335. X
  1336. XlinNum = 0;
  1337. XoCol = 0;
  1338. Xnc.ncIStrm = f;
  1339. Xpp = nextc();
  1340. Xdo
  1341. X   {
  1342. X   if ((T_END + 256) == *pp) pp = nextc();
  1343. X   if (*pp <= 256)
  1344. X      nl = FALSE;
  1345. X   else
  1346. X      {
  1347. X      switch (*pp - 256)
  1348. X         {
  1349. X         case T_TAB:
  1350. X            spcs = p->TabWid - ((nc.ncICol - 1) % p->TabWid) - 1;
  1351. X            nc.ncICol += spcs;
  1352. X            oCol += spcs;
  1353. X            nl = FALSE;
  1354. X            break;
  1355. X         case T_UNDEF:
  1356. X            malf0 (eUndef, fp->filName, linNum + 1);
  1357. X            /* Falls through.*/
  1358. X         case T_STRB:
  1359. X         case T_STRE:
  1360. X            nl = FALSE;
  1361. X            break;
  1362. X         case T_LINEE:
  1363. X            ++linNum;
  1364. X            nc.ncICol = 0;
  1365. X            if (oCol > mc)
  1366. X               {
  1367. X               mcl = linNum;
  1368. X               mc = oCol;
  1369. X               }
  1370. X            nl = TRUE;
  1371. X            oCol = 0;
  1372. X            break;
  1373. X         case T_COLE:
  1374. X         case T_PAGEE:
  1375. X            if (oCol > mc)
  1376. X               {
  1377. X               mcl = linNum + 1;
  1378. X               mc = oCol;
  1379. X               }
  1380. X            oCol = 0;
  1381. X            break;
  1382. X         case T_EOF:
  1383. X            if (!nl) malf0 (eEOF, fp->filName, linNum + 1);
  1384. X            if (oCol > mc)
  1385. X               {
  1386. X               mcl = linNum + 1;
  1387. X               mc = oCol;
  1388. X               }
  1389. X            break;
  1390. X         default:
  1391. X            malf1 (eIntern, "cvfile", __LINE__);
  1392. X            break;
  1393. X         }
  1394. X      }
  1395. X   }
  1396. Xwhile ((T_EOF + 256) != *pp++);
  1397. Xif (0 == mc)
  1398. X   { /* Empty file.*/
  1399. X   *pcp = 0;
  1400. X   return;
  1401. X   }
  1402. Xlines = linNum;
  1403. X--mc;
  1404. Xif (p->AutoFil)
  1405. X   {
  1406. X   for (pc = p->Columns; (1 != pc) && (mc > p->AutoCol[pc]); --pc)
  1407. X      ;
  1408. X   *porp = (mc <= p->AutoLnd);
  1409. X   }
  1410. Xelse
  1411. X   {
  1412. X   pc = p->Columns;
  1413. X   *porp = (0 != p->AutoLnd);
  1414. X   }
  1415. X*pcp = pc;
  1416. Xrewind (f);
  1417. XlinCont = FALSE;
  1418. XoutBufE = &outBuf[MOUTBUF];
  1419. Xif (DB(D_FILE))
  1420. X   FPRINTF (stderr,
  1421. X      "preScan: widest line: %u (%u cols)\n\ttotal lines: %u\n\tinitial page columns: %u %s\n",
  1422. X      mcl, mc, linNum, pc, *porp ? "portrait" : "landscape");
  1423. X}
  1424. X
  1425. X/* psputc - append one byte to output buffer */
  1426. X
  1427. XPRIVATE void psputc (c)
  1428. XR1 rcharT c; /* Byte to append.*/
  1429. X
  1430. X/* Function:
  1431. X *    Store c in the output buffer.  Handle long lines and buffer overflow.
  1432. X * Algorithm:
  1433. X *    psLinL is the current number of bytes already output on the current
  1434. X *    output line.  Just ignore a newline after another newline.
  1435. X * Returns:
  1436. X *    
  1437. X * Notes:
  1438. X *    1) This is inefficient.  We shouldn't be copying so many bytes around.
  1439. X *       We should use pointers instead.
  1440. X */
  1441. X{
  1442. Xif ('\n' == c)
  1443. X   {
  1444. X   if (0 != psLinL)
  1445. X      {
  1446. X      *outBufP++ = c;
  1447. X      psLinL = 0;
  1448. X      }
  1449. X   }
  1450. Xelse
  1451. X   {
  1452. X   *outBufP++ = c;
  1453. X   ++psLinL;
  1454. X   }
  1455. Xif (outBufP >= outBufE) mpsputc();
  1456. X}
  1457. X
  1458. X/* putDim - write a dimension to output buffer */
  1459. X
  1460. XPRIVATE void putDim (a, v)
  1461. XcStrT  a; /* Abbreviation string for dimension.*/
  1462. Xdouble v; /* Value of dimension.*/
  1463. X
  1464. X/* Function:
  1465. X *    Write a def directly to the output stream.
  1466. X * Algorithm:
  1467. X *    
  1468. X * Returns:
  1469. X *    
  1470. X * Notes:
  1471. X *    1) Two decimal places are enough precision for printers with up
  1472. X *       to 7200 dots per inch resolution.
  1473. X */
  1474. X{
  1475. XFPRINTF (psos, "/%s %.2f %s\n", a, v, PDEF);
  1476. X}
  1477. X
  1478. X/* putDimO - write a dimension to output buffer */
  1479. X
  1480. XPRIVATE void putDimO (a, v)
  1481. XcStrT  a; /* Abbreviation string for dimension.*/
  1482. Xdouble v; /* Value of dimension.*/
  1483. X
  1484. X/* Function:
  1485. X *    Store a def in the output buffer.
  1486. X * Algorithm:
  1487. X *    The first call to PSPUTC makes psLinL nonzero for the second call.
  1488. X *    Otherwise the second call would be ignored.  The second call
  1489. X *    checks for output buffer overflow.
  1490. X * Returns:
  1491. X *    
  1492. X * Notes:
  1493. X *    
  1494. X */
  1495. X{
  1496. XPSPUTC ('/');
  1497. XSPRINTF (outBufP, "%s %.2f %s", a, v, PDEF);
  1498. XoutBufP = strend (outBufP);
  1499. XPSPUTC ('\n');
  1500. X}
  1501. X
  1502. X/* putFnts - write definition for each font used */
  1503. X
  1504. XPRIVATE void putFnts()
  1505. X
  1506. X/* Function:
  1507. X *    Create the list of all fonts used by all files in the job.
  1508. X *    Output reencode commands for all fonts used except symbol fonts.
  1509. X * Algorithm:
  1510. X *    Loop through each file.  Call addFnt() for each font.
  1511. X *    Then loop through each font.
  1512. X * Returns:
  1513. X *    
  1514. X * Notes:
  1515. X *    
  1516. X */
  1517. X{
  1518. XR1 filT   *fp;  /* Steps through fil[].*/
  1519. XR2 fontT  *fnp; /* Steps through fonts[].*/
  1520. XR3 paramT *p;   /* &fp->filPara.*/
  1521. X
  1522. Xfor (fp = &fil[1]; fp != filp; ++fp)
  1523. X   {
  1524. X   p = &fp->filPara;
  1525. X   addFnt (p->FixWid ? p->FWFont : p->VWFont, FALSE);
  1526. X   addFnt (p->FootFnt, FALSE);
  1527. X   addFnt (p->HeadFnt, FALSE);
  1528. X   addFnt (p->LNFnt,   FALSE);
  1529. X   addFnt (p->SymbFnt, TRUE);
  1530. X   }
  1531. Xfor (fnp = fonts; fnp != fontP; ++fnp)
  1532. X   {
  1533. X   if (!fnp->fntSymb)
  1534. X      FPRINTF (psos, "/%sE /%s %s\n", fnp->fntName, fnp->fntName, REENCOD);
  1535. X   }
  1536. X}
  1537. X
  1538. X/* putPage - Write one page to psos */
  1539. XPRIVATE void putPage (fp, pp, pn, tp, nb)
  1540. XR4 filT     *fp; /* Points to file data.*/
  1541. XR7 pageT    *pp; /* Points to data for page.*/
  1542. XR5 unsigned  pn; /* Page number.*/
  1543. XR6 unsigned  tp; /* Total number of pages in file.*/
  1544. XR2 long      nb; /* Number of bytes to copy from temporary file.*/
  1545. X
  1546. X/* Function:
  1547. X *    
  1548. X * Algorithm:
  1549. X *    The width available for one column is the (effective) page width
  1550. X *    less the left and right margins and column separation gutters,
  1551. X *    all divided by the number of columns.
  1552. X *    The maximum number of lines per column is the (effective) page
  1553. X *    height less the top and bottom margins and header and footer,
  1554. X *    divided by the distance between lines, then rounded down.
  1555. X *
  1556. X *    Output all the dimensions, then copy bytes.
  1557. X * Returns:
  1558. X *    
  1559. X * Notes:
  1560. X *    1) I have no idea if the TxtVert code is the right thing to do.
  1561. X *       The theory is that landscaped vertical text should be like
  1562. X *       portrait horizontal text, and vice versa.
  1563. X *    2) It would be faster to copy the bytes in big chunks, not
  1564. X *       one at a time.
  1565. X */
  1566. X{
  1567. XR1 rcharT  c;        /* Current byte from temp file.*/
  1568. XR3 paramT *p = &fp->filPara;
  1569. X   double  cw;       /* Page column width.*/
  1570. X   double  ePageHt;  /* Effective page height.*/
  1571. X   double  ePageWid; /* Effective page width.*/
  1572. X   double  eLMarg;   /* Effective left margin.*/
  1573. X   double  eRMarg;   /* Effective right margin.*/
  1574. X   double  eTMarg;   /* Effective top margin.*/
  1575. X   double  eBMarg;   /* Effective bottom margin.*/
  1576. X
  1577. Xmfseek (psts, pp->pgPos, 0, pstfn);
  1578. XFPRINTF (psos, "%%%%Page: %s-%u %u\n", fp->filName, pn, pn + totPag);
  1579. XFPUTS (topBuf, psos);
  1580. Xif (pp->pgPor != p->TxtVert)
  1581. X   {
  1582. X   ePageHt  = p->PageHt;
  1583. X   ePageWid = p->PageWid;
  1584. X   eLMarg   = p->LMargP;
  1585. X   eRMarg   = p->RMargP;
  1586. X   eTMarg   = p->TMargP;
  1587. X   eBMarg   = p->BMargP;
  1588. X   FPRINTF (psos, "/%s{}%s\n", PROTATE, PDEF);
  1589. X   }
  1590. Xelse
  1591. X   {
  1592. X   ePageHt  = p->PageWid;
  1593. X   ePageWid = p->PageHt;
  1594. X   eLMarg   = p->LMargL;
  1595. X   eRMarg   = p->RMargL;
  1596. X   eTMarg   = p->TMargL;
  1597. X   eBMarg   = p->BMargL;
  1598. X   FPRINTF (psos, "/%s/%s %s %s\n",
  1599. X            PROTATE, (90 == p->LandRot) ? PROTPOS : PROTNEG, PLOAD, PDEF);
  1600. X   }
  1601. Xif (eTMarg + p->HeadHt > ePageHt)
  1602. X   malf1 (eBigHd, p->TMargP + p->HeadHt, p->PageHt);
  1603. Xcw = (ePageWid - eLMarg - eRMarg - (pp->pgCols - 1) * p->ColSep) / pp->pgCols;
  1604. Xif (cw <= 0.0) malf1 (eColWid, cw);
  1605. XputDim (LMARGIN, eLMarg);
  1606. XputDim (RMARGIN, eRMarg);
  1607. XputDim (BMARGIN, eBMarg);
  1608. XputDim (TMARGIN, eTMarg);
  1609. XputDim (PPAGEWD, ePageWid);
  1610. XputDim (PPAGEHT, ePageHt);
  1611. XFPRINTF (psos, "/%s %u %s\n", PPAGEN, pn, PDEF);
  1612. XFPRINTF (psos, "/%s(- %u / %u -)%s\n", PPAGES, pn, tp, PDEF);
  1613. XputDim (FOLDIND, p->FoldInd);
  1614. XputDim (TOPSKIP, p->TSkip);
  1615. XputDim (PDX, cw + p->ColSep);
  1616. XFPRINTF (psos, "%s\n", PPAGEB);
  1617. Xwhile (nb--)
  1618. X   {
  1619. X   c = getc (psts);
  1620. X   if (EOF == c)
  1621. X      {
  1622. X      if (ferror (psts)) malf1 (eRead, pstfn);
  1623. X      malf1 (eUEOF, pstfn);
  1624. X      }
  1625. X   PUTC (c, psos);
  1626. X   }
  1627. XFPRINTF (psos, "%s\n%%%%PageTrailer\n", PPAGEE);
  1628. X}
  1629. X
  1630. X/* readenv - process environment variables */
  1631. X
  1632. XPRIVATE void readenv()
  1633. X
  1634. X/* Function:
  1635. X *    Execute any commands in the environment.
  1636. X * Algorithm:
  1637. X *    Linear search through the environment variables for any matches.
  1638. X *    Call cmd() on a match.
  1639. X * Notes:
  1640. X *    1) Ignore CZPATH.  It's handled elsewhere.
  1641. X */
  1642. X{
  1643. Xextern cStrT *environ;         /* (5V).*/
  1644. XR4     bStrT *ep;              /* Steps through environment variables.*/
  1645. XR3     bStrT  cp;              /* General purpose.*/
  1646. XR2     bStrT  cp2;             /* General purpose.*/
  1647. XR1     bStrT  cp3;             /* General purpose.*/
  1648. X       byteT  cbuf[MLINE + 1]; /* Command buffer.*/
  1649. X
  1650. Xfor (ep = (bStrT *) environ; NULBSTR != (cp = *ep++);)
  1651. X   {
  1652. X   if ((NULBSTR != (cp3 = prefix (S(ENVPRE), cp))) &&
  1653. X       (NULBSTR == prefix (S(CZPATH), cp)))
  1654. X      {
  1655. X      cp2 = cbuf;
  1656. X      for (; (EOS != B(*cp3)) && ('=' != B(*cp3)); ++cp3)
  1657. X         {
  1658. X         if (cp2 == &cbuf[MLINE]) malf1 (eMLine, ep[-1], MLINE);
  1659. X         *cp2++ = B(*cp3);
  1660. X         }
  1661. X      if (('=' == B(*cp3)) && (EOS != B(cp3[1])))
  1662. X         {
  1663. X         ++cp3;
  1664. X         *cp2 = EOS;
  1665. X         cmd (cbuf, cp3, "Environment", 0);
  1666. X         }
  1667. X      }
  1668. X   }
  1669. X}
  1670. X
  1671. X/* readpth - read every command file on the path */
  1672. X
  1673. XPRIVATE void readpth (cfn)
  1674. XR7 bStrT cfn; /* Command file name.*/
  1675. X
  1676. X/* Function:
  1677. X *    Read and execute every cz.rc file on the search path.
  1678. X *    Copy every cz.ps file to output.
  1679. X * Algorithm:
  1680. X *    Starting at the beginning of the path,
  1681. X *    and working toward the end, copy each segment into
  1682. X *    fnbuf[], append the command file name, and try to open the
  1683. X *    file.  If the file can be opened, call readrc() on it, then
  1684. X *    close it and proceed to the next segment.
  1685. X */
  1686. X{
  1687. XR1     bStrT   p1;           /* Step through path.*/
  1688. XR2     bStrT   p2;           /* Step through path.*/
  1689. XR3     streamT f;            /* Command file.*/
  1690. XR4     int     i;            /* Path length.*/
  1691. XR5     int     l;            /* Length of command file name.*/
  1692. XR6     int     m;            /* Max path length.*/
  1693. Xextern cStrT   getenv();     /* (3).*/
  1694. X       byteT   fnbuf[MFILE]; /* Buffer for current file name.*/
  1695. X
  1696. Xl = strlen ((cStrT) cfn);
  1697. Xm = MFILE - 1 - l - MAX (strlen (CZSUF), strlen (PSSUF));
  1698. Xp1 = path;
  1699. Xif (DB(D_CMD)) FPRINTF (stderr, "readpth %s\n", cfn);
  1700. Xdo
  1701. X   {
  1702. X   p2 = bStrChr (p1, PATHSEP);
  1703. X   i = ((NULBSTR == p2) ? strlen (p1) : p2 - p1);
  1704. X   if ((0 == i) || (i > m)) malf1 (eMPath, m, p1);
  1705. X   (void) strncpy ((cStrT) fnbuf, (cStrT) p1, i);
  1706. X   p1 = &fnbuf[i];
  1707. X   if ('/' != B(p1[-1])) *p1++ = '/';
  1708. X   STRCPY ((cStrT) p1, (cStrT) cfn);
  1709. X   p1 += l;
  1710. X   STRCPY ((cStrT) p1, CZSUF);
  1711. X   f = fopen ((cStrT) fnbuf, "r");
  1712. X   if (NULSTRM == f)
  1713. X      {
  1714. X      if (DB(D_CMD)) FPRINTF (stderr, "trying %s...failed\n", fnbuf);
  1715. X      }
  1716. X   else
  1717. X      {
  1718. X      if (DB(D_CMD)) FPRINTF (stderr, "trying %s...ok\n", fnbuf);
  1719. X      readrc (f, fnbuf);
  1720. X      if (fclose (f)) malf0 (eClose, fnbuf);
  1721. X      }
  1722. X   STRCPY ((cStrT) p1, PSSUF);
  1723. X   f = fopen ((cStrT) fnbuf, "r");
  1724. X   if (NULSTRM == f)
  1725. X      {
  1726. X      if (DB(D_CMD)) FPRINTF (stderr, "trying %s...failed\n", fnbuf);
  1727. X      }
  1728. X   else
  1729. X      {
  1730. X      if (DB(D_CMD)) FPRINTF (stderr, "trying %s...ok\n", fnbuf);
  1731. X      FPRINTF (psos, "%%%%BeginFile: %s\n", fnbuf);
  1732. X      mfcopy (f, 0, fnbuf, psos, 1, Out);
  1733. X      if (fclose (f)) malf0 (eClose, fnbuf);
  1734. X      FPUTS ("%%EndFile\n", psos);
  1735. X      }
  1736. X   if (NULBSTR != p2) p1 = p2 + 1;
  1737. X   }
  1738. Xwhile (NULBSTR != p2);
  1739. X}
  1740. X
  1741. X/* readrc - read one command file */
  1742. X
  1743. XPRIVATE void readrc (f, fn)
  1744. XR4 streamT f;  /* File.*/
  1745. XR3 bStrT   fn; /* File name.*/
  1746. X
  1747. X/* Function:
  1748. X *    Read through one command file and execute each command.
  1749. X * Algorithm:
  1750. X *    Read each line.  Strip comments and trailing white space.
  1751. X *    Skip leading white
  1752. X *    space.  Find command.  Put NUL at end of it.  Skip white
  1753. X *    space.  Find value.  Call cmd().
  1754. X * Notes:
  1755. X *    
  1756. X */
  1757. X{
  1758. XR1 bStrT    cp;        /* General purpose.*/
  1759. XR2 bStrT    cmdp;      /* Points to command.*/
  1760. X   unsigned ln = 0;    /* Current line number.*/
  1761. X   byteT    lb[MLINE]; /* Input line buffer.*/
  1762. X
  1763. Xwhile (NULBSTR != getlic (lb, MLINE, f, fn, &ln, 1, COMMENT))
  1764. X   {
  1765. X   for (cp = lb; ' ' == B(*cp); ++cp)
  1766. X      ;
  1767. X   cmdp = cp++;
  1768. X   for (; (EOS != B(*cp)) && (' ' != B(*cp)); ++cp)
  1769. X      ;
  1770. X   if (EOS != B(*cp))
  1771. X      {
  1772. X      *cp++ = EOS;
  1773. X      for (; ' ' == B(*cp); ++cp)
  1774. X         ;
  1775. X      if (EOS != B(*cp)) cmd (cmdp, cp, fn, ln);
  1776. X      else malf0 (eNoArgL, fn, ln, lb);
  1777. X      }
  1778. X   }
  1779. X}
  1780. X
  1781. X/* undef - undefine one state-octet pair or one whole state */
  1782. X
  1783. XPRIVATE void undef (ss, os)
  1784. X   bStrT ss; /* State as a string.*/
  1785. XR1 bStrT os; /* Octet as a string.*/
  1786. X
  1787. X/* Function:
  1788. X *    cz0 starts out configured for ISO 8859/1.  For other character
  1789. X *    sets, it's sometimes necessary to undefine state-octet pairs.
  1790. X * Algorithm:
  1791. X *    Convert state to number.  If "octet" is All, zap the whole state.
  1792. X *    Otherwise, convert octet to number and zap that entry.
  1793. X * Returns:
  1794. X *    
  1795. X * Notes:
  1796. X *    1) Dynamic memory is not freed.
  1797. X */
  1798. X{
  1799. XR2 unsigned  o;    /* Octet.*/
  1800. XR3 unsigned  s;    /* State.*/
  1801. XR4 soT      *sop1; /* Current soT.*/
  1802. XR5 stateT   *sp;   /* Points to current stateT.*/
  1803. X
  1804. Xs = mra2u (ss, NULBSTR, FALSE, S("State"), (unsigned) 0, (unsigned) MSTATE,
  1805. X           (bStrT *) NULL);
  1806. Xif (bStrEQ (S("All"), os))
  1807. X   states[s] = (stateT *) NULL;
  1808. Xelse
  1809. X   {
  1810. X   o = mra2u (os, NULBSTR, FALSE, "Octet", (unsigned) 0, (unsigned) 255,
  1811. X              (bStrT *) NULL);
  1812. X   sp = states[s];
  1813. X   if (((stateT *) NULL) != sp)
  1814. X      {
  1815. X      sop1 = ((soT *) sp) + o;
  1816. X      sop1->so_ps = NULBSTR;
  1817. X      }
  1818. X   }
  1819. X}
  1820. X
  1821. X/* main - main function                            */
  1822. X
  1823. XPUBLIC void main (argc, argv)
  1824. X   int    argc; /* Number of arguments.*/
  1825. XR2 bStrT *argv; /* Points to array of argument strings.*/
  1826. X
  1827. X/* Function:
  1828. X *    Main function.
  1829. X * Algorithm:
  1830. X *    If there's a -o option, open the output stream.
  1831. X *    Call init(), etc.
  1832. X *    Step through command line arguments and call cmd() on them.
  1833. X *    Step through files and call cvfile() on each.
  1834. X * Notes:
  1835. X *    
  1836. X */
  1837. X
  1838. X{
  1839. XR1 bStrT cp; /* Used in argument decoding.*/
  1840. XR3 filT *fp; /* Steps through fil[].*/
  1841. X
  1842. X++argv;
  1843. Xcp = *argv++;
  1844. Xif ((argc >= 3) && (bStrEQ (S("-o"), cp)))
  1845. X   {
  1846. X   cp = *argv++;
  1847. X   if (PIPECHR != B(*cp))
  1848. X      psos = fopen ((cStrT) cp, "w");
  1849. X   else if (EOS == B(cp[1]))
  1850. X      malf1 (eNoPipe, PIPECHR);
  1851. X   else
  1852. X      psos = popen ((cStrT) &cp[1], "w");
  1853. X   if (NULSTRM == psos) malf1 (eOpen, cp);
  1854. X   Out = cp;
  1855. X   cp = *argv++;
  1856. X   }
  1857. Xinit();
  1858. XheadCom();
  1859. Xipath();
  1860. Xreadpth ("header");
  1861. XFPUTS ("%%EndComments\n", psos);
  1862. XFPRINTF (psos, "/%s/load load def\n/%s/def %s def\n/Version(cz%d.%d)%s\n",
  1863. X         PLOAD, PDEF, PLOAD, FRZ_MAJ, FRZ_MIN, PDEF);
  1864. Xreadpth ("prolog-beg");
  1865. Xreadenv();
  1866. Xwhile ((NULBSTR != cp) && ('-' == B(*cp)))
  1867. X   {
  1868. X   ++cp;
  1869. X   if (NULBSTR == *argv) malf1 (eNoArg, cp);
  1870. X   else cmd (cp, *argv++, sCLine, 0);
  1871. X   cp = *argv++;
  1872. X   }
  1873. Xif (NULBSTR != cp) usage();
  1874. Xif (filp == &fil[1]) malf1 (eNoFile);
  1875. Xif (DB(D_JOB)) FPRINTF (stderr, "%d file(s)\n", filp - fil - 1);
  1876. XputFnts();
  1877. Xreadpth ("prolog-end");
  1878. XFPUTS ("%%EndProlog\n", psos);
  1879. Xif (Reverse)
  1880. X   {
  1881. X   for (fp = filp - 1; fp != fil;)
  1882. X      cvfile (fp--);
  1883. X   }
  1884. Xelse
  1885. X   {
  1886. X   for (fp = &fil[1]; fp != filp;)
  1887. X      cvfile (fp++);
  1888. X   }
  1889. XFPRINTF (psos, "%%%%Trailer\n%%%%Pages: %u\n", totPag);
  1890. XdocFnts();
  1891. Xif (EndCtlD) PUTC (4, psos);
  1892. Xmfflush (psos, Out);
  1893. Xif ((PIPECHR == B(*Out)) ? pclose (psos) : fclose (psos)) malf0 (eClose, Out);
  1894. Xif ((NULCSTR != pstfn) && unlink (pstfn)) malf0 (eUnlink, pstfn);
  1895. Xexit (0);
  1896. X}
  1897. END_OF_FILE
  1898. if test 54952 -ne `wc -c <'cz0.c'`; then
  1899.     echo shar: \"'cz0.c'\" unpacked with wrong size!
  1900. fi
  1901. # end of 'cz0.c'
  1902. fi
  1903. echo shar: End of archive 11 \(of 14\).
  1904. cp /dev/null ark11isdone
  1905. MISSING=""
  1906. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  1907.     if test ! -f ark${I}isdone ; then
  1908.     MISSING="${MISSING} ${I}"
  1909.     fi
  1910. done
  1911. if test "${MISSING}" = "" ; then
  1912.     echo You have unpacked all 14 archives.
  1913.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1914. else
  1915.     echo You still need to unpack the following archives:
  1916.     echo "        " ${MISSING}
  1917. fi
  1918. ##  End of shell archive.
  1919. exit 0
  1920.  
  1921.